/*
  @author: remy sharp / http://remysharp.com
  @url: http://remysharp.com/2008/04/01/wiki-to-html-using-javascript/
  @license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
  @version: 1.0
  
  Can extend String or be used stand alone - just change the flag at the top of the script.

  @modified: alexander demin / http://easy-coding.blogspot.com
*/

(function () {
    
var extendString = true;

if (extendString) {
    String.prototype.wiki2html = wiki2html;
} else {
    window.wiki2html = wiki2html;
}

function wiki2html(s) {
    if (extendString) {
        s = this;
    }

    // lists need to be done using a function to allow for recusive calls
    function list(str) {
        return str.replace(/(?:(?:(?:^|\n)[\*#].*)+)/g, function (m) {  // (?=[\*#])
            var type = m.match(/(^|\n)#/) ? 'OL' : 'UL';
            // strip first layer of list
            m = m.replace(/(^|\n)[\*#][ ]{0,1}/g, "$1");
            m = list(m);
            return '<' + type + '><li>' + m.replace(/^\n/, '').split(/\n/).join('</li><li>') + '</li></' + type + '>';
        });
    }
    
    function format_code(s) { // format code blocks
        var lang = "cpp";
        s = s.replace(/^[\n\r]+/g, '').replace(/[\n\r]+$/g, '');
        s = s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
        s = s.replace(/  /g, "&nbsp;&nbsp;");
        if (s.indexOf("[==========]") != -1) lang = "css";
        if (s.indexOf(".cmd") != -1) lang = "dos";
        if (s.indexOf("/EHsc") != -1) lang = "dos";
        return '<pre><code class="' + lang + '">' + s + '</code></pre>';
    }

    var plains = []

    s = s.replace(/@@([\S\s]+?)@@/g, function (m, l) { // copy out the non-wiki blocks
        plains[plains.length] = l;
        return "@plain:" + (plains.length - 1);
    });

    var codes = []

    s = s.replace(/{{{([\S\s]+?)}}}/g, function (m, l) { // copy out the code blocks
        codes[codes.length] = l;
        return "@code:" + (codes.length - 1);
    });

    s = list(s
        
        /* Block elements */

        .replace(/(?:^|\n+)([^# =\*<].+)(?:\n+|$)/gm, function (m, l) {
            if (l.match(/^\^+$/)) return l;
            return "\n<p>" + l + "</p>\n";
        })

        .replace(/(?:^|\n)[ ]{2}(.*)+/g, function (m, l) { // blockquotes
            if (l.match(/^\s+$/)) return m;
            return '<blockquote>' + l + '</blockquote>';
        })

        .replace(/-{3,}/g, function (m) { // hr
            return '<hr />';
        })
    
        .replace(/(?:^|\n)([=]+)(.*)\1/g, function (m, l, t) { // headings
            return '<h' + l.length + '>' + t + '</h' + l.length + '>';
        })
    
        /* Inline elements */

        .replace(/(''')(.*?)\1/g, function (m, t, l) { // bold
            return '<strong>' + l + '</strong>';
        })
    
        .replace(/''(.*?)''/g, function (m, l) { // italic
            return '<em>' + l + '</em>';
        })
   
        .replace(/`(.*?)`/g, function (m, l) { // code
            return '<code>' + l + '</code>';
        })
    
        .replace(/ -- /g, " &#151; ")

        // [url img]
        .replace(/\[(http:\/\/.*?) +(http:\/\/.*?\.(?:jpeg|jpg|gif|png))\]/g, function (m, l, i) {
            return '<a href="' + l + '"><img src="' + i + '"/></a>';
        })

        // [image{ descr}]
        .replace(/\[(http:\/\/.*?\.(?:jpeg|jpg|gif|png))(| +\S+?)\]/g, function (m, l, t) {
            return t ? ('<a href="' + l + '">' + t + '</a>') :
                       ('<a rel="lytebox" href="' + l + '"><img src="' + l + '"/></a>');
        })

        // [youtube]
        .replace(/\[http\:\/\/(?:|www)\.youtube\.com\/watch\?v=(\S+?)\]/g, function (m, i) {
            return '<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/' + i + '&rel=0&color1=0xb1b1b1&color2=0xcfcfcf&feature=player_embedded&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/' + i + '&rel=0&color1=0xb1b1b1&color2=0xcfcfcf&feature=player_embedded&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="344"></embed></object>';
        })

        // [url{ descr}]
        .replace(/\[(http:\/\/.*?)(?:| +(.+?))\]/g, function (m, l, t) {
            return '<a href="' + l + '">' + (t ? t : l) + '</a>';
        })
    ); 

    // Put back the code blocks and format them.
    s = s.replace(/@code\:(\d)+/g, function(m, l) {
        return format_code(codes[l]);
    });

    // Put back the non-wiki blocks.
    s = s.replace(/@plain\:(\d+)/g, function(m, l) {
        return plains[l];
    });

    // Delete all trailing line endings after </blockquote>, </pre>, </p>, <ul> and <ol>.
    s = s.replace(/(<\/(blockquote|pre|p|ol|ul)>)[\n\r]+/gi, function (m, l) {
        return l;
    });

    // Delete whitespaces between headings and <p>.
    s = s.replace(/(<\/h\d+>)[\S\s]+?(<p>)/ig, function (m, t, p) {
        return t + p;
    });

    // Delete all </p>.
    s = s.replace(/<\/p>/ig, "")

    return s;
}
    
})();
